package org.amse.mARICa;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.net.*;

import org.amse.mARICa.game.*;
import org.amse.mARICa.model.*;
import org.amse.mARICa.model.impl.*;
import org.amse.mARICa.model.impl.players.*;

public class Tournament {
	
	private int myCountGames;
	private IBoard myBoard;
	private IGame myGame;
	private InitPlayer myInitPlayer1;
	private InitPlayer myInitPlayer2;
	private boolean myIsStep;
	
	private static class InitPlayer{
		String name;
		int maxLevel;
		boolean isRand;
	}
	
	public Tournament (int countGames, int countPot, int countBeans){
		myCountGames = countGames;
		Settings.setCountBeans(countBeans);
		Settings.setCountPots(countPot);		
	}
	
	public void setPlayer(String className, int maxLevel, boolean rand){
		if (myInitPlayer1 == null){
			myInitPlayer1 = new InitPlayer();
			myInitPlayer1.name = className;
			myInitPlayer1.maxLevel = maxLevel;
			myInitPlayer1.isRand = rand;
		}else{
			myInitPlayer2 = new InitPlayer();
			myInitPlayer2.name = className;
			myInitPlayer2.maxLevel = maxLevel;
			myInitPlayer2.isRand = rand;
		}
	}
	
	private class IntellectProvider extends URLClassLoader{
	
		public IntellectProvider(URL[] urls, ClassLoader parent) {
			super(urls, parent);			
		}

		public void addURL(URL url) {
			super.addURL(url);
		}
		
	}
	

	private boolean initGame(){
		myBoard = new Board (Settings.getCountPots(), Settings.getCountBeans());
		myGame = new Game(myBoard);		 
		Class cl = null;
		AIPlayer ai1;
		AIPlayer ai2;
		Object [] obs = new Object [] {EKindPlayer.COMP, myGame};
		int k;
		try {
			if ( (k = myInitPlayer1.name.indexOf(".jar")) >= 0){
				String jar = myInitPlayer1.name.substring(0, k+4);
				String name = myInitPlayer1.name.substring(k+5, myInitPlayer1.name.length());
				IntellectProvider url = new IntellectProvider(new URL[0], this.getClass().getClassLoader());
				url.addURL(new URL("file:" + jar));
				cl = url.loadClass(name); 
			}else{		
				cl = Class.forName(myInitPlayer1.name, false, this.getClass().getClassLoader());
			}
			Constructor constructor = cl.getConstructor(EKindPlayer.class, IGame.class);
			ai1 = (AIPlayer) constructor.newInstance(obs);
			ai1.setMaxLevel(myInitPlayer1.maxLevel);
			ai1.setRandomChoose(myInitPlayer1.isRand);
			
			if ( (k = myInitPlayer2.name.indexOf(".jar")) >= 0){
				String jar = myInitPlayer2.name.substring(0, k+4);
				String name = myInitPlayer2.name.substring(k+5, myInitPlayer2.name.length());
				IntellectProvider url = new IntellectProvider(new URL[0], this.getClass().getClassLoader());
				url.addURL(new URL("file:" + jar));
				cl = url.loadClass(name); 
			}else{		
				cl = Class.forName(myInitPlayer2.name, false, this.getClass().getClassLoader());
			}
			constructor = cl.getConstructor(EKindPlayer.class, IGame.class);
			ai2 = (AIPlayer) constructor.newInstance(obs);		
			ai2.setMaxLevel(myInitPlayer2.maxLevel);
			ai2.setRandomChoose(myInitPlayer2.isRand);
		} catch (ClassNotFoundException e) {
			Logger.getInctanse().println(e.toString());
			return false;
		} catch (InstantiationException e) {
			Logger.getInctanse().println(e.toString());
			return false;
		} catch (IllegalAccessException e) {
			Logger.getInctanse().println(e.toString());
			return false;
		} catch (SecurityException e) {
			Logger.getInctanse().println(e.toString());
			return false;
		} catch (NoSuchMethodException e) {
			Logger.getInctanse().println(e.toString());
			return false;
		} catch (IllegalArgumentException e) {
			Logger.getInctanse().println(e.toString());
			return false;
		} catch (InvocationTargetException e) {
			Logger.getInctanse().println(e.toString());
			return false;
		} catch (MalformedURLException e) {
			Logger.getInctanse().println(e.toString());
			return false;
		}		
		myGame.setPlayer1(ai1);
		myGame.setPlayer2(ai2);
		return true;
	}
	
	public boolean startTournament(){
		if (myIsStep){
			return startOnStep();
		}
		return startOnGame();
	}
	
	public boolean startOnStep(){
		Logger.getInctanse().setStepGame(true);
		return startOnGame();
	}
	
	public boolean startOnGame(){
		int countWinPl1 = 0;
		int countNoWinner = 0;
		for(int i = 0; i < myCountGames; i++){
			if (!initGame()){
				return false;
			}
			((Game)myGame).start();
			while ( !myGame.isWin()){
				try {
					Thread.sleep(3000);
				} catch (InterruptedException e) {
					Logger.getInctanse().println(e.toString());
				}
			}
			if (myGame.getWiner() == EKindWins.WINDOWN){
				countWinPl1++;
			}else if (myGame.getWiner() == EKindWins.NOWINNER){
				countNoWinner++;
			}
			System.out.println("Game " + ( i+1) + ": " + myGame.getWiner());			
		}
		System.out.println();
		System.out.print("Player Down: " + myGame.getPlayer1().getClass().getSimpleName());
		System.out.print(" with maxLevel=" + ((AIPlayer)myGame.getPlayer1()).getMaxLevel());
		System.out.println(" and rand=" + ((AIPlayer)myGame.getPlayer1()).isRandomChoose());
		System.out.print("Player   Up: " + myGame.getPlayer2().getClass().getSimpleName());
		System.out.print(" with maxLevel=" + ((AIPlayer)myGame.getPlayer2()).getMaxLevel());
		System.out.println(" and rand=" + ((AIPlayer)myGame.getPlayer2()).isRandomChoose());
		System.out.println("PlayerDown wins " + countWinPl1);
		System.out.println("PlayerUp   wins " + ( myCountGames - countNoWinner - countWinPl1));
		System.out.println("Drawn game   is " + countNoWinner);
		return true;
	}

	public void setStep(boolean b) {
		myIsStep = b;		
	}
	
	public boolean isStep(){
		return myIsStep;
	}

}
